package com.gitee.feizns.convert;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;

/**
 * @author feizns
 * @since 2019/5/19 0019
 */
public abstract class NumberConvertUtils {

    private static final Map<Class<?>, Function<Number, Number>> NUMBER_MAP = new HashMap<>();

    static {
        {
            NUMBER_MAP.put(byte.class, Number::byteValue);
            NUMBER_MAP.put(short.class, Number::shortValue);
            NUMBER_MAP.put(int.class, Number::intValue);
            NUMBER_MAP.put(long.class, Number::longValue);
            NUMBER_MAP.put(float.class, Number::floatValue);
            NUMBER_MAP.put(double.class, Number::doubleValue);
            NUMBER_MAP.put(Byte.class, Number::byteValue);
            NUMBER_MAP.put(Short.class, Number::shortValue);
            NUMBER_MAP.put(Integer.class, Number::intValue);
            NUMBER_MAP.put(Long.class, Number::longValue);
            NUMBER_MAP.put(Float.class, Number::floatValue);
            NUMBER_MAP.put(Double.class, Number::doubleValue);
            NUMBER_MAP.put(BigDecimal.class, number -> BigDecimal.valueOf(number.doubleValue()));
            NUMBER_MAP.put(BigInteger.class, number -> BigInteger.valueOf(number.longValue()));
        }
    }

    public static <T extends Number> T to(Object original, Class<?> targetType) {
        if ( targetType.isAssignableFrom(original.getClass()) == false ) {
            Function<Number, Number> convertFun = NUMBER_MAP.get(targetType);
            if ( convertFun != null ) {
                Number value = original instanceof Number
                        ? (Number) original
                        : toDouble(original);
                if ( value != null )
                    return (T) convertFun.apply(value);
            }
            return null;
        }
        return (T) original;
    }

    private static final Double toDouble(Object original) {
        try {
            return Double.valueOf(original.toString());
        } catch (NumberFormatException e) {
            return null;
        }
    }

    /**
     * 注册转换方式
     * @param targetType
     * @param fun
     */
    public static final void registry(Class<? extends Number> targetType, Function<Number, Number> fun) {
        NUMBER_MAP.put(targetType, fun);
    }

    /**
     * 是否支持
     * @param clz
     * @return
     */
    public static final boolean isSupport(Class<?> clz) {
        return NUMBER_MAP.containsKey(clz);
    }

}
